# Copyright 2010 Giacomo Alzetta
# This file is part of "LimberEditor" and is distribuhited under the
# terms of the MIT license.

import unittest
from limber import componentchooser
from limber import abilities as limb_abilities
from mocks import *


class TestComponentChooser(unittest.TestCase):

    def setUp(self):
        self.component_1 = object()
        self.component_2 = object()
        self.component_3 = object()

        self.abilities_1 = (
            limb_abilities.TEXT,
            limb_abilities.HTML_TEXT,
            limb_abilities.MOINMOIN_TEXT)

        self.abilities_2 = (
            limb_abilities.BINARY,
            limb_abilities.IMAGE_BINARY)

        self.abilities_3 = (
            limb_abilities.TEXT,
            limb_abilities.HTML_TEXT)

    def testIntantiate(self):
        try:
            component_chooser = componentchooser.ComponentChooser()
        except Exception,e:
            self.fail('Could not instantiate the ability manager: %s' % e)

    def testRegisterComponent(self):
        component_chooser = componentchooser.ComponentChooser()

        self.assertEqual(component_chooser.number_of_components(), 0,
                         'The ability manager has some registered components.')
        self.assertEqual(component_chooser.components(), (),
                         'The ability manager has some registered components.')

        component_chooser.register_component(self.component_1, self.abilities_1)
        self.assertEqual(component_chooser.number_of_components(), 1,
                         'The ability manager does not have 1 registered component.')
        self.assertEqual(component_chooser.components(), (self.component_1,),
                         'The components returned are not right.')

        component_chooser.register_component(self.component_2, self.abilities_2)
        self.assertEqual(component_chooser.number_of_components(), 2,
                         'The ability manager does not have 2 registered components.')
        self.assertEqual(sorted(component_chooser.components()),
                         sorted((self.component_1, self.component_2)),
                         'The components returned are not right.')

    def testUnregisterComponent(self):
        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)

        component_chooser.unregister_component(self.component_1)
        self.assertEqual(component_chooser.number_of_components(), 1,
                         'The component was not unregistered.')
        self.assertEqual(component_chooser.components(), (self.component_2,),
                         'The components returned are not right.')

        component_chooser.unregister_component(self.component_2)
        self.assertEqual(component_chooser.number_of_components(), 0,
                         'The component was not unregistered.')
        self.assertEqual(component_chooser.components(), (),
                         'The components returned are not right.')

        self.assertRaises(componentchooser.ComponentChooserError,
                          component_chooser.unregister_component,
                          self.component_2)

    def testGetAbilities(self):

        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)

        self.assertEqual(component_chooser.get_abilities(self.component_1),
                         self.abilities_1,
                         'The abilities returned are wrong.')
        self.assertEqual(component_chooser.get_abilities(self.component_2),
                         self.abilities_2,
                         'The abilities returned are wrong.')

        self.assertRaises(componentchooser.ComponentChooserError,
                          component_chooser.get_abilities,
                          object())

    def testGetComponent(self):

        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)
        component_chooser.register_component(self.component_3, self.abilities_3)

        abilities = (limb_abilities.BINARY, limb_abilities.IMAGE_BINARY)
        reqs = (True, False)
        for required in reqs:
            got, got_ab = component_chooser.get_component(abilities, required)

            self.assertEqual(got, self.component_2,
                             'Returned the wrong component.')
            self.assertEqual(got_ab, self.abilities_2,
                             'Returned the wrong abilities.')

        abilities = (limb_abilities.TEXT, limb_abilities.HTML_TEXT,
                     limb_abilities.MOINMOIN_TEXT)

        for required in reqs:

            got, got_ab = component_chooser.get_component(abilities, required)
            self.assertEqual(got, self.component_1,
                             'Returned the wrong component.')
            self.assertEqual(got_ab, self.abilities_1,
                             'Returned the wrong abilities.')

        got, got_ab = component_chooser.get_component(abilities, all_required=False)
        self.assertTrue(got in (self.component_1, self.component_3))
        if got_ab == self.abilities_1:
            must_be = self.component_1
        elif got_ab == self.abilities_3:
            must_be = self.component_3
        else:
            self.fail('Returned wrong abilities.')

        self.assertEqual(got, must_be,
                         'The component and the abilities returned '
                         'are not associated.')

    def testGetComponentRaiseComponentChooserError(self):
        component_chooser = componentchooser.ComponentChooser()

        abilities = (limb_abilities.TEXT,
                     limb_abilities.HTML_TEXT,
                     limb_abilities.VIEW)

        try:
            got, got_ab = component_chooser.get_component(abilities)
            self.fail('Should not be able to obtain this component.')
        except componentchooser.ComponentChooserError:
            pass
        except Exception,e:
            self.fail('Got unexpected exception: %r' % e)

        component_chooser.register_component(self.component_1, self.abilities_1)

        try:
            got, got_ab = component_chooser.get_component(abilities)
            self.fail('Should not be able to obtain this component.')
        except componentchooser.ComponentChooserError:
            pass
        except Exception,e:
            self.fail('Got unexpected exception: %r' % e)

        abilities = (
            limb_abilities.VIEW,
            limb_abilities.FLOATABLE_VIEW)

        try:
            got, got_ab = component_chooser.get_component(abilities,
                                                        all_required=False)
            self.fail('Should not be able to obtain any component.')
        except componentchooser.ComponentChooserError:
            pass
        except Exception,e:
            self.fail('Unexpected exception: %r.' % e)

    def testFetchComponent(self):
        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)

        req_abilities = (
            limb_abilities.TEXT,
            limb_abilities.HTML_TEXT)

        other_abilities = (
            limb_abilities.MOINMOIN_TEXT,)

        got, got_ab = component_chooser.fetch_component(req_abilities, other_abilities)
        self.assertEqual(got, self.component_1, 'Got the wrong component.')
        self.assertEqual(got_ab, self.abilities_1, 'Got the wrong abilities.')

        req_abilities = (
            limb_abilities.TEXT,)

        other_abilities = (
            limb_abilities.MOINMOIN_TEXT,
            limb_abilities.HTML_TEXT)

        got, got_ab = component_chooser.fetch_component(req_abilities, other_abilities)
        self.assertEqual(got, self.component_1, 'Got the wrong component.')
        self.assertEqual(got_ab, self.abilities_1, 'Got the wrong abilities.')

    def testFetchComponentRaisesComponentChooserError(self):
        component_chooser = componentchooser.ComponentChooser()

        try:
            got, got_ab = component_chooser.fetch_component((), ())
            self.fail('Should not be able to query a component '
                      'without any ability required.')
        except componentchooser.ComponentChooserError:
            pass
        except Exception,e:
            self.fail('Unexpected exception: %r.' % e)

        component_chooser.register_component(self.component_1, self.abilities_1)

        try:
            got, got_ab = component_chooser.fetch_component(self.abilities_2)
            self.fail('Should not be able to do an invalid query.')
        except componentchooser.ComponentChooserError:
            pass
        except Exception,e:
            self.fail('Unexpected exception: %r.' % e)

    def testFetchComponentGetRightPriorities(self):
        component_chooser = componentchooser.ComponentChooser()

        component_4 = object()
        abilities_4 = (
            limb_abilities.TEXT,
            limb_abilities.HTML_TEXT,
            limb_abilities.VIEW)

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)
        component_chooser.register_component(self.component_3, self.abilities_3)
        component_chooser.register_component(component_4, abilities_4)

        req_abilities = (
            limb_abilities.TEXT,
            limb_abilities.HTML_TEXT,)

        other_abilities = (
            limb_abilities.MOINMOIN_TEXT,
            limb_abilities.VIEW)

        priorities = (1, 2)

        got, got_ab = component_chooser.fetch_component(req_abilities,
                                                      other_abilities,
                                                      priorities)
        self.assertEqual(got, component_4, 'Got the wrong component.')
        self.assertEqual(got_ab, abilities_4, 'Got the wrong abilities.')

        priorities = (2, 1)

        got, got_ab = component_chooser.fetch_component(req_abilities,
                                                      other_abilities,
                                                      priorities)

        self.assertEqual(got, self.component_1, 'Got the wrong component.')
        self.assertEqual(got_ab, self.abilities_1, 'Got the wrong abilities.')

    def testGetComponents(self):
        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)
        component_chooser.register_component(self.component_3, self.abilities_3)

        abilities = (limb_abilities.TEXT,)

        gots, gots_abs = component_chooser.get_components(abilities)
        gots, gots_abs = sorted(gots), sorted(gots_abs)

        right_gots = sorted((self.component_1, self.component_3))
        right_abs = sorted((self.abilities_1, self.abilities_3))

        self.assertEqual(gots, right_gots, 'Got the wrong components.')
        self.assertEqual(gots_abs, right_abs, 'Got the wrong abilities.')

        abilities = (
            limb_abilities.TEXT,
            limb_abilities.HTML_TEXT,
            limb_abilities.MOINMOIN_TEXT)

        gots, gots_abs = component_chooser.get_components(abilities,
                                                        all_required=False)
        gots, gots_abs = sorted(gots), sorted(gots_abs)

        self.assertEqual(gots, right_gots, 'Got the wrong components.')
        self.assertEqual(gots_abs, right_abs, 'Got the wrong abilities.')

    def testGetComponentsIsSorted(self):
        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)
        component_chooser.register_component(self.component_3, self.abilities_3)

        abilities = (
            limb_abilities.TEXT,
            limb_abilities.HTML_TEXT,
            limb_abilities.MOINMOIN_TEXT)

        right_gots = (
            self.component_1,
            self.component_3)

        right_abils = (
            self.abilities_1,
            self.abilities_3)

        gots, abils = component_chooser.get_components(abilities,
                                                     all_required=False)

        self.assertEqual(zip(gots, abils), zip(right_gots, right_abils),
                         'The value were different or not sorted.')

    def testGetComponentsRaisesComponentChooserError(self):
        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)
        component_chooser.register_component(self.component_3, self.abilities_3)

        abils = (
            limb_abilities.VIEW,
            limb_abilities.FLOATABLE_VIEW)

        try:
            component_chooser.get_components(abils)
            self.fail('Should not be able to obtain components.')
        except componentchooser.ComponentChooserError:
            pass
        except Exception,e:
            self.fail('Unexpected exception: %r.' % e)

    def testFetchComponents(self):
        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)
        component_chooser.register_component(self.component_3, self.abilities_3)

        req_abilities = (limb_abilities.TEXT, )
        other_abilities = (limb_abilities.HTML_TEXT,
                           limb_abilities.MOINMOIN_TEXT)

        components, abilities = component_chooser.fetch_components(
                                req_abilities, other_abilities)

        self.assertEqual(len(components), 2, 'Too many components returned.')
        self.assertEqual(len(components), 2, 'Too many abilitites returned.')

        self.assertTrue(self.component_1 in components, 'Wrong components.')
        self.assertTrue(self.component_3 in components, 'Wrong components.')
        self.assertTrue(self.abilities_1 in abilities, 'Wrong abilities.')
        self.assertTrue(self.abilities_3 in abilities, 'Wrong abilities.')

    def testFetchComponentsIsSorted(self):
        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)
        component_chooser.register_component(self.component_3, self.abilities_3)

        req_abilities = (limb_abilities.TEXT, )
        other_abilities = (limb_abilities.HTML_TEXT,
                           limb_abilities.MOINMOIN_TEXT)

        components, abilities = component_chooser.fetch_components(
                                req_abilities, other_abilities)

        right_gots = (
            (self.component_1, self.abilities_1),
            (self.component_3, self.abilities_3))

        self.assertEqual(tuple(zip(components, abilities)), right_gots,
                         'Got unsorted components or wrong components.')

    def testFetchComponentsRaisesComponentChooserError(self):
        component_chooser = componentchooser.ComponentChooser()

        component_chooser.register_component(self.component_1, self.abilities_1)
        component_chooser.register_component(self.component_2, self.abilities_2)
        component_chooser.register_component(self.component_3, self.abilities_3)

        req_abilities = (limb_abilities.VIEW,)
        other_abilities = (
            limb_abilities.TEXT,
            limb_abilities.HTML_TEXT,
            limb_abilities.MOINMOIN_TEXT)

        try:
            gots, abils = component_chooser.fetch_components(req_abilities,
                                                           other_abilities)
            self.fail('Should not be able to fullfil this query.')
        except componentchooser.ComponentChooserError:
            pass
        except Exception,e:
            self.fail('Unexpected exception: %r.' % e)
